/*
* @Author: 窦子滨<zibin_5257@163.com>
* @Date: 2019-04-10
 */
package TcpPack

//基础包

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"io"
	"strconv"
)

type PackBase struct {
	//1 开头 2字节
	Length   int16 //2 长度 2字节
	DeviceId int32 //3 终端号 4字节
	Direct string //4 命令字 1字节
	Source   string //5 来源 1字节 高4位 0-主站 1-终端
	GunId    string //5 枪号 1字节 低4位 枪号 0-为充电桩
	TranType int8   //6 传输类型 1字节
	Data     []byte //7 数据部分 n字节
	//8 结束标示 1字节 0x68
	SignSum  int32  //9 校验和 4字节
}

type Pack struct {
	Data []byte //整体数据
}

//进行数据打包 包括基础数据和业务数据
func PackAll(DeviceId int32,Direct string,Source string,GunId string,TranType int8,Data []byte) []byte{
	//基础数据
	pack := &PackBase{
		Length:   0,
		DeviceId: DeviceId,
		Direct:Direct ,
		Source:   Source,
		GunId:    GunId,
		TranType: TranType,
		Data: Data,
	}

	buf1 := new(bytes.Buffer)
	pack.Pack(buf1)
	//数据重新组装 修改长度 尾部附加校验和
	return  reformPack(buf1.Bytes())
}


//重组包数据
func reformPack(data []byte) []byte {
	//计算长度
	//lenttt := uint16(len(buf1.Bytes()) + 4)
	//获取数据包真实长度
	//lenttt := packLen(data)
	//fmt.Println("数据长度：", lenttt)
	//int转byte
	var buffer bytes.Buffer
	binary.Write(&buffer, binary.LittleEndian, packLen(data))

	b := buffer.Bytes()

	//ss=append(ss[:index],ss[index+1:]...)
	//去掉前2字节的虚假长度
	data = append(data[:0], data[2:]...)

	//fmt.Println("去掉长度后的byte：",data)

	//开头数据
	a := []byte{117, 114}
	//
	a = append(a, b...)
	a = append(a, data...)
	//fmt.Println(hex.EncodeToString(buffer.Bytes()))

	//计算校验和
	var buf2 bytes.Buffer
	binary.Write(&buf2, binary.LittleEndian, byteSum(a))

	a = append(a, buf2.Bytes()...)

	//fmt.Println("最终十六进制：",hex.EncodeToString(a))
	return a
}

/**
检测长度值是否正确
@param data 待检测的值
@param number 给定的值
 */
func (p *Pack) CheckLenght(number int16) error {
	var err error

	if (byteLen(p.Data) != number) {
		return errors.New("长度校验错误")
	}

	return err
}

/**
检测校验和
@param data 待检测的值
@param number 给定的值
 */
func (p *Pack) CheckSum(number int32) error {
	var err error
	sum := byteSum(p.Data[0:len(p.Data)-4])
	//fmt.Println("计算校验和：", sum)
	if (sum != number) {
		return errors.New("校验和错误")
	}

	return err
}

/**
针对基础包解码
 */
func (p *PackBase) Unpack(reader io.Reader, size int) error {
	var err error

	//1 获取头
	var headByte [2]byte

	err = binary.Read(reader, binary.LittleEndian, &headByte)

	//p.Head = hex.EncodeToString(headByte[:])
	//2 获取长度
	err = binary.Read(reader, binary.LittleEndian, &p.Length)
	//3 获取设备号
	err = binary.Read(reader, binary.LittleEndian, &p.DeviceId)

	//4 获取指令
	var d [1]byte
	err = binary.Read(reader, binary.LittleEndian, &d)
	p.Direct = hex.EncodeToString(d[:])

	//获取5  来源和枪号
	var five [1]byte
	err = binary.Read(reader, binary.LittleEndian, &five)

	fiveStr := hex.EncodeToString(five[:])

	p.Source = string(fiveStr[0])
	p.GunId = string(fiveStr[1])

	//获取6 传输类型
	var tran [1]byte
	err = binary.Read(reader, binary.LittleEndian, &tran)

	bb, err := strconv.Atoi(hex.EncodeToString(tran[:]))
	p.TranType = int8(bb)

	//获取数据部分
	dataSize := size - 16 //11个头 5个尾  68+校验和
	p.Data = make([]byte, dataSize)

	//fmt.Println("数据长度：", dataSize)
	err = binary.Read(reader, binary.LittleEndian, &p.Data)

	//9 去除结束标示
	var a [1]byte
	err = binary.Read(reader, binary.LittleEndian, &a)
	_ = a

	//10 校验和
	err = binary.Read(reader, binary.LittleEndian, &p.SignSum)

	//var b [16]byte
	//err=binary.Read(reader, binary.LittleEndian, b)
	//fmt.Println(err)
	//fmt.Println(b)


	return err
}

//基础包 编码打包
func (p *PackBase) Pack(writer io.Writer) error {
	var err error

	err = binary.Write(writer, binary.LittleEndian, &p.Length)
	err = binary.Write(writer, binary.LittleEndian, &p.DeviceId)

	//写入指令
	dir, _ := hex.DecodeString(p.Direct)
	err = binary.Write(writer, binary.LittleEndian, dir)

	//处理来源和枪号
	sou, _ := hex.DecodeString(p.Source + p.GunId)
	err = binary.Write(writer, binary.LittleEndian, sou)

	//传输类型
	a := int8(p.TranType)
	err = binary.Write(writer, binary.LittleEndian, a)

	//数据部分
	err = binary.Write(writer, binary.LittleEndian, &p.Data)

	//结束标示
	end, _ := hex.DecodeString("68")
	err = binary.Write(writer, binary.LittleEndian, end)

	return err
}

//计算[]byte的和
func byteSum(data []byte) int32 {
	// calculate checksum
	//sum := adler32.New()
	var sum int32

	for _, v := range data {
		sum = sum + int32(v)
	}

	return sum
}

//计算打包后的数据长度 加上后4位校验和
func packLen(data []byte) uint16 {
	return uint16(len(data) + 4)
}

//计算byte的长度
func byteLen(data []byte) int16 {
	l := len(data) - 2
	return int16(l)
}
